package com.hmdp.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hmdp.dto.Result;
import com.hmdp.dto.ScrollResult;
import com.hmdp.dto.UserDTO;
import com.hmdp.entity.Blog;
import com.hmdp.entity.Follow;
import com.hmdp.entity.User;
import com.hmdp.mapper.BlogMapper;
import com.hmdp.service.IBlogService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.service.IFollowService;
import com.hmdp.service.IUserService;
import com.hmdp.utils.UserHolder;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.hmdp.constants.RedisConstants.BLOG_LIKED_KEY;
import static com.hmdp.constants.RedisConstants.USER_FEED_KEY;
import static com.hmdp.constants.SystemConstants.MAX_PAGE_SIZE;
import static com.hmdp.constants.SystemConstants.ROLL_MAX_PAGE_SIZE;


@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService {

    @Resource
    private IUserService iUserService;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private IFollowService iFollowService;

    @Override
    public Result queryHotBlog(Integer current) {

        // 根据用户查询
        Page<Blog> page = this.query()
                .orderByDesc("liked")
                .page(new Page<>(current, MAX_PAGE_SIZE));
        // 获取当前页数据
        List<Blog> records = page.getRecords();
        // 查询用户
        records.forEach(this::queryBlogUser);

        return Result.ok(records);
    }

    @Override
    public Result queryBlog(Long id) {

        Blog blog = this.getById(id);
        if (blog == null) {
            return Result.fail("笔记不存在!");
        }
        //查询用户信息
        queryBlogUser(blog);
        return Result.ok(blog);
    }

    @Override
    public Result saveBlog(Blog blog) {
        // 获取登录用户
        UserDTO user = UserHolder.getUser();
        blog.setUserId(user.getId());
        // 保存探店博文
        boolean saveSuccess = this.save(blog);
        if (!saveSuccess) {
            return Result.fail("新增失败");

        }
        //TODO Feed流推送消息给粉丝
        //1、查询笔记作者的粉丝
        List<Follow> fans = iFollowService.list(Wrappers.<Follow>query().eq("follow_user_id", user.getId()));
        //2、推送笔记id给粉丝
        long currentTimeMillis = System.currentTimeMillis();

        for (Follow fan : fans) {
            //粉丝id
            Long userId = fan.getUserId();
            //TODO 推送
            stringRedisTemplate.opsForZSet().add(USER_FEED_KEY + userId, blog.getId().toString(), currentTimeMillis);
        }
        //返回id
        return Result.ok(blog.getId());
    }

    @Override
    public Result queryMyBlog(Integer current) {
        // 获取登录用户
        UserDTO user = UserHolder.getUser();
        // 根据用户查询
        Page<Blog> page = this.query()
                .eq("user_id", user.getId()).last("order by create_time desc").page(new Page<>(current, MAX_PAGE_SIZE));
        // 获取当前页数据
        List<Blog> records = page.getRecords();
        return Result.ok(records);
    }

    @Override
    public Result likeBlog(Long id) {

        //1、获取用户
        Long loginUserId = UserHolder.getUser().getId();
        //2、判断当前用户是否已经点赞

        Double score = stringRedisTemplate.opsForZSet().score(BLOG_LIKED_KEY + id, loginUserId.toString());

        //3、未点赞 进行点赞
        if (score == null) {
            boolean isSuccess = this.update().setSql("liked = liked + 1").eq("id", id).update();
            if (isSuccess) {
                stringRedisTemplate.opsForZSet().add(BLOG_LIKED_KEY + id, loginUserId.toString(), System.currentTimeMillis());
            }
        } else {
            //4、点赞了 取消点赞
            boolean isSuccess = this.update().setSql("liked = liked - 1").eq("id", id).update();
            if (isSuccess) {
                stringRedisTemplate.opsForZSet().remove(BLOG_LIKED_KEY + id, loginUserId.toString());
            }
        }
        return Result.ok();
    }

    /**
     * 根据博客id查询点赞排行榜
     *
     * @author Yhans
     * @date 2024/2/25 14:36
     */
    @Override
    public Result queryBlogLikeList(Long id) {

        //查询最先点赞的5位用户
        Set<String> top5 = stringRedisTemplate.opsForZSet().range(BLOG_LIKED_KEY + id, 0, 4);
        if (top5 == null || top5.isEmpty()) {
            return Result.ok(Collections.emptyList());
        }
        List<UserDTO> top5UserList = top5.stream().map(s -> {
            UserDTO userDTO = new UserDTO();
            User topUser = iUserService.getById(s);
            BeanUtil.copyProperties(topUser, userDTO);
            return userDTO;
        }).collect(Collectors.toList());
        return Result.ok(top5UserList);
    }

    //查询其他用户主页的笔记
    @Override
    public Result queryOtherUserBlogs(Long id, Integer current) {

        // 根据用户查询
        Page<Blog> page = this.query()
                .eq("user_id", id).last("order by create_time desc").page(new Page<>(current, MAX_PAGE_SIZE));
        // 获取当前页数据
        List<Blog> records = page.getRecords();
        return Result.ok(records);
    }

    /**
     * 滚动分页查询关注用户的笔记
     *
     * @param max    上一次查询的最小值 本次查询的最大值
     * @param offset 查多少条
     * @return Result
     * @author Yhans
     * @date 2024/2/26 15:49
     */
    @Override
    public Result queryBlogOfFollow(Long max, Integer offset) {
        //返回值
        ScrollResult scrollResult = new ScrollResult();

        //1、获取登录用户
        Long id = UserHolder.getUser().getId();
        String key = USER_FEED_KEY + id;
        //2、TODO 从redis中获取用户的收件箱(博主id,时间戳)  ZREVRANGEBYSCORE key Max Min LIMIT offset count
        Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet()
                .reverseRangeByScoreWithScores(key, 0, max, offset, ROLL_MAX_PAGE_SIZE);
        // 3.非空判断
        if (typedTuples == null || typedTuples.isEmpty()) {
            return Result.ok();
        }

        List<Blog> blogPageList = new ArrayList<>();
        long minTime = 0;  //当前查询的最小分数
        int os = 1;  //首次为0 第二次为1  (最后一个元素出现的个数)
        for (ZSetOperations.TypedTuple<String> typedTuple : typedTuples) { //5 4 4 2 2
            //获取博客id
            String blogId = typedTuple.getValue();
            Blog blog = getById(blogId);
            if (blog != null) {
                blogPageList.add(blog);
            }
            //获取分数
            long score = typedTuple.getScore().longValue();
            if (score == minTime) {
                os++;
            } else {
                minTime = score;
                //重置
                os = 1;
            }
        }
        //封装博主信息和用户是否点赞信息
        for (Blog blog : blogPageList) {
            queryBlogUser(blog);
        }
        scrollResult.setList(blogPageList);
        scrollResult.setMinTime(minTime);
        scrollResult.setOffset(os);
        return Result.ok(scrollResult);
    }

    private void queryBlogUser(Blog blog) {

        //未登录则不判断当前用户是否点赞
        if (UserHolder.getUser() == null) {
            return;
        }
        //登录用户的id
        Long loginUserId = UserHolder.getUser().getId();
        //探店笔记id
        Long blogId = blog.getId();
        //笔记用户id
        Long blogUserId = blog.getUserId();

        //1、判断当前用户是否点赞了笔记
        Double score = stringRedisTemplate.opsForZSet().score(BLOG_LIKED_KEY + blogId, loginUserId.toString());
        if (score != null) {
            blog.setIsLike(true);
        }
        //2、查询用户信息
        User user = iUserService.getById(blogUserId);
        blog.setName(user.getNickName());
        blog.setIcon(user.getIcon());
    }
}
